from typing import Any
import numpy as np
from scipy.spatial import ConvexHull

from ..pipeline.pipeline import PipeModule, status_manage, Port
from ..pipeline.portTypes import PortType, PortTypeHint
from ..dataclass.terminologies import GeoResults, GeneralProps, Units
from ..dataclass.results import SingleResult, UnitResult


@status_manage
class ConvexHullCenter(PipeModule):
    """Calcualte the center of the convex hull of point samples"""

    def __init__(self, mname: str | None = None, auto_run: bool = True,
                 points_table: PortTypeHint.TableData | None = None,
                 by_xy: bool = True
                 ) -> None:
        """Initialize ConvexHullCenter object.

        Parameters
        ----------
        points_table: PortTypeHint.TableData | None
            The table contains the point samples.

        by_xy: bool, default: True
            If True, the center will be calculated by the x and y coordinates.
            If False, the center will be calculated by the longitude and latitude.
        """
        super().__init__(mname, auto_run)

        self._ports_in = {"InputTable": Port(ptype=PortType.TableData, data=points_table, pdoc="The table contains the point samples.")}
        self._ports_out = {"OutputCenter": Port(ptype=PortType.SingleResult, pdoc="The coordinates of the center")}

        self.by_xy = by_xy

    @property
    def InputTable(self) -> None:
         raise AttributeError("Property 'InputTable' is write-only.")
    
    @InputTable.setter
    def InputTable(self, value: PortTypeHint.TableData | None) -> None:
        self._ports_in["InputTable"].data = value

    @property
    def OutputCenter(self) -> PortTypeHint.SingleResult | None:
        return self._ports_out["OutputCenter"].data
    
    def set_cal_params(self, reset: bool = True) -> None:
        return None
    
    def execute(self) -> PortTypeHint.SingleResult | None:
        points_table: PortTypeHint.TableData | None = self._ports_in["InputTable"].data

        if points_table is None or points_table.empty:
            self._ports_out["OutputCenter"].data = None
            return None

        if self.by_xy:
            points_coord = points_table[[GeneralProps.XCoordinate, GeneralProps.YCoordinate]].values
        else:
            points_coord = points_table[[GeneralProps.Longitude, GeneralProps.Latitude]].values

        if points_coord.shape[0] == 1:
            center = points_coord
        elif points_coord.shape[0] == 2:
            center = np.mean(points_coord, axis=0)
        else:
            hull = ConvexHull(points_coord)
            center = np.mean(points_coord[hull.vertices], axis=0)
        
        # Create result object
        if self.by_xy:
            center = [
                UnitResult(name=GeneralProps.XCoordinate, title="X坐标", unit=Units.m, value=center[0]),
                UnitResult(name=GeneralProps.YCoordinate, title="Y坐标", unit=Units.m, value=center[1])
            ]
        else:
            center = [
                UnitResult(name=GeneralProps.Longitude, title="经度", unit=Units.DEGREE, value=center[0]),
                UnitResult(name=GeneralProps.Latitude, title="纬度", unit=Units.DEGREE, value=center[1])
            ]
        output = SingleResult(result=center)
        
        self._ports_out["OutputCenter"].data = output
        return output



